﻿using System;
using System.Reflection;
using System.Web.UI;
using System.Web.UI.WebControls;
using Portal.Core.ActionFlow;
using Portal.Core.Binding;
using Portal.Core.Binding.FormBuilder;
using Portal.Core.Security;
using Portal.Data;
using Portal.Core.Web.UI.Controls;
using Portal.Data.Entity;
using Portal.Data.Security;
using Binder = Portal.Core.Binding.Binder;
using Module = Portal.Data.Entity.Module;

namespace App_Code.Modules
{
    /// <summary>
    /// Summary description for GenericModule
    /// </summary>
    public class GenericModule : ActionUserControl
    {
        #region private members

        protected Module Module;
        private Control _content;
        private BaseObject _editObject;
        private Control _message;
        private Button _save, _delete;

        #endregion

        #region config

        //List
        protected virtual Type EditType
        {
            get { return null; }
        }

        protected virtual string ViewMembers
        {
            get { return null; }
        }

        protected virtual string ViewDataSource
        {
            get { return "ListAll"; }
        }

        protected virtual object[] DataSourceParameters
        {
            get { return null; }
        }

        protected virtual Button CmdSave
        {
            get { return _save ?? (_save = (Button)FindControl("Save")); }
        }

        protected virtual Button CmdDelete
        {
            get { return _delete ?? (_delete = (Button)FindControl("Delete")); }
        }

        protected virtual Control Root
        {
            get { return _content ?? (_content = FindControl("Content")); }
        }

        protected virtual Control LblMessage
        {
            get { return _message ?? (_message = FindControl("Message")); }
        }

        protected virtual object EditObject
        {
            get { return _editObject; }
        }

        /// <summary>
        /// Tien` Kiem tra permission theo gia tri dien vao, ko kiem tra theo action
        /// </summary>
        protected virtual int PermissionManual
        {
            get { return Permission.NONE; }
        }

        #endregion

        #region implement

        protected virtual void CheckPermission(string action)
        {
//            if (PermissionManual != Permission.NONE)
//            {
//                //check by permission manual
//                if (!SecurityProvider.Instance.HasPermission(PortalContext.CurrentUser, PermissionManual))
//                {
//                    throw new AccessException("Bạn không có quyền thực hiện hành động này!");
//                }
//                return;
//            }
//            int p = Permission.NONE;
//            bool flag = true;
//            switch (action)
//            {
//                case "edit":
//                    p = Permission.CanEditModule();
//                    break;
//                case "new":
//                    p = Permission.CanEditModule();
//                    break;
//                case "list":
//                    p = Permission.CanViewModule();
//                    break;
//                case "lists":
//                    p = Permission.CanViewModule();
//                    break;
//                case "view":
//                    p = Permission.CanViewModule();
//                    break;
//                case "none":    //ignore check permission
//                    flag = false;
//                    break;
//                default:
//                    p = Permission.CanViewModule();
//                    break;
//            }
//            if (flag) SecurityProvider.Instance.CheckPermission(Module.ID, p);
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            Module = Module.FindByPageName(ModuleName);
            if (Module == null)
            {
                var control =
                    new LiteralControl(
                        "<span style='color:red'>Does not exist module[" + ModuleName + "], please creat OnInit(EventArgs e) method to fix this error.</span>");
                Controls.Add(control);
                return;
            }

            CheckPermission(Action);
            switch (Action)
            {
                case "new":
                    LoadNewForm();
                    break;
                case "edit":
                    LoadEditForm();
                    break;
                case "list":
                    LoadListForm();
                    break;
                case "sort":
                    LoadListForm();
                    break;
            }
        }

        private Button BtnCommand(string btnName)
        {
            //            var btn = new Button { Text = btnName, ID = btnName + Root.Controls.Count, ToolTip = btnName };
            var btn = new Button { Text = btnName, ID = btnName, ToolTip = btnName };
            switch (btnName)
            {
                case "New":
                    btn.Click += New_Click;
                    break;
                case "Save":
                    btn.Click += Save_Click;
                    btn.ID = btnName;
                    btn.ValidationGroup = EditType.Name;
                    break;
                case "Delete":
                    btn.Click += Delete_Click;
                    btn.ToolTip = @"Cho vào thùng rác";
                    btn.Attributes.Add("onclick", "return confirm('Are you sure delete this object?');");
                    break;
                case "Cancel":
                    btn.Click += Cancel_Click;
                    break;
            }

            btn.CssClass = "Command" + btnName;
            return btn;
        }

        #region List

        protected virtual void New_Click(object sender, EventArgs e)
        {
            Forward("new");
        }

        protected virtual void SortContent_Click(object sender, EventArgs e)
        {
            Forward("sort");
        }

        protected void LoadListForm()
        {
            var context = new BuildContext { BindData = !Page.IsPostBack, DataSourceParameters = DataSourceParameters };
            context.Delete += CommandDelete;
            context.Edit += CommandEdit;


            Root.Controls.Add(Builder.RenderView(EditType, ViewMembers, ViewDataSource, Command.Edit | Command.Delete,
                                                 context));

            Root.Controls.Add(BtnCommand("New"));

            context.OnDataBind();
        }

        private void CommandEdit(object id)
        {
            OnCommanEdit(id);
        }

        private void CommandDelete(object id)
        {
            MethodInfo m = EditType.GetMethod("FindByPrimaryKey");
            var obj = m.Invoke(null, new object[] { Convert.ChangeType(id, ReflectionHelper.FindPrimaryKeyType(EditType).PropertyType) });
            if (obj != null) OnCommanDelete(obj);
        }
        protected virtual void OnCommanEdit(object id)
        {
            ItemEdit(id);
        }
        protected virtual void OnCommanDelete(object obj)
        {
            ((BaseObject)obj).Delete();
            Forward("delete");
        }
        #endregion

        #region build form new/edit

        public BaseObject FindByPrimaryKey(string key = "id")
        {
            return FindByPrimaryKey(EditType, key);
        }

        /// <summary>
        /// Lấy object và lưu lại giá trị cũ vào OriginalData field trước khi thay đổi giá trị
        /// </summary>
        /// <param name="type"> </param>
        /// <param name="key"></param>
        /// <returns>Trả về NULL nếu không tồn tại</returns>
        public BaseObject FindByPrimaryKey(Type type, string key = "id")
        {
            var obj = Binder.TransferObject(type, key);
            if (obj != null)
            {
                var data = (BaseObject)obj;
                data.OriginalData = data.Clone();   //keep orginal data before changed
                return data;
            }
            return null;
        }

        protected void LoadNewForm()
        {
            var context = new BuildContext { BindData = !IsPostBack, PageRoot = Page };

            var btnSave = BtnCommand("Save");
            context.ValidationGroup = btnSave.ValidationGroup;

            Root.Controls.Add(Builder.BuildForm(EditType, context));

            Root.Controls.Add(btnSave);
            Root.Controls.Add(BtnCommand("Cancel"));

            context.OnDataBind();
        }

        protected void LoadEditForm()
        {
            _editObject = FindByPrimaryKey();
            if (_editObject == null)
            {
                if (CmdSave != null)
                    CmdSave.Visible = CmdSave.Enabled = false;
                LblMessage.Visible = true;
                return;
            }

            var context = new BuildContext { BindData = !Page.IsPostBack, EditObject = _editObject };


            Button btnSave = BtnCommand("Save");
            context.ValidationGroup = btnSave.ValidationGroup;
            var builForm = Builder.BuildForm(EditType, context);
            Root.Controls.Add(builForm);

            Root.Controls.Add(btnSave);
            Root.Controls.Add(BtnCommand("Delete"));
            Root.Controls.Add(BtnCommand("Cancel"));

            context.OnDataBind();

            Binder.SetData(Root.Controls[0], _editObject, new BindContext());
        }

        #endregion

        #region Save - Edit Handler

        protected BaseObject GetObject()
        {
            if (!Page.IsValid)
            {
                return null;
            }
            object obj;

            if (Action == "edit" || (_editObject != null))
            {
                obj = _editObject != null ? FindByPrimaryKey() : _editObject;
                obj = Binder.GetData(obj, Root.Controls[0], new BindContext());
            }
            else
            {
                obj = Binder.GetData(EditType, Root.Controls[0], new BindContext());
            }

            return (BaseObject)obj;
        }

        protected virtual void Save_Click(object sender, EventArgs e)
        {
            var obj = GetObject();

            if (obj != null)
            {
                BeforeSave(obj);
                if (Action == "edit" || (_editObject != null))
                {
                    obj.Update();
                }
                else
                {
                    obj.Save();
                }
                _editObject = obj;
                AfterSave(obj);
            }
        }

        protected virtual void BeforeSave(object obj)
        {
        }

        protected virtual void AfterSave(object obj)
        {
            Forward("save");
        }

        protected virtual void Cancel_Click(object sender, EventArgs e)
        {
            Forward("cancel");
        }

        protected virtual void Delete_Click(object sender, EventArgs e)
        {
            var obj = GetObject();
            if (obj == null) return;
            obj.Delete();
            Forward("delete");
        }

        #endregion

        #endregion

        #region My Paging

        protected void AddPagingTool(Control[] objs, int totalrecord, int pagesize, string parampaging)
        {
            if (objs.Length <= 0) return;
            foreach (Control t in objs)
            {
                var mypaging = new MyPaging { CssClass = "paging", MyTotalCount = totalrecord, MyPageSize = pagesize };
                if (!string.IsNullOrEmpty(parampaging))
                    mypaging.MyParamPaging = parampaging;

                t.Controls.Add(mypaging);
            }
        }

        /// <summary>
        /// Get the current page index
        /// </summary>
        /// <param name="paramPaging">if NULL or empty then set default is "page"</param>
        /// <returns></returns>
        protected int GetCurrentPage(string paramPaging = null)
        {
            var iCurrPage = 1;
            if (string.IsNullOrEmpty(paramPaging))
                paramPaging = "page";

            if (Request.QueryString[paramPaging] != null)
            {
                try
                {
                    iCurrPage = Convert.ToInt32(Request.QueryString[paramPaging]);
                }
                catch
                {
                }
            }
            iCurrPage--;

            return iCurrPage;
        }

        #endregion
    }
}